package Utils.reflect;

import org.apache.poi.ss.formula.functions.T;

import java.lang.reflect.*;

/**
 * 反射工具类
 *
 * @author d11yu
 */
public final class ReflectUtils {
    private ReflectUtils() {
    }

    /**
     * 根据字段名获取某个public的field（包括父类）
     *
     * @param obj  待处理的对象
     * @param name 字段名
     * @return
     */
    public static Field getField(Object obj, String name) throws NoSuchFieldException {
        Field fd = obj.getClass().getField(name);
        fd.setAccessible(true);
        return fd;
    }

    /**
     * 根据字段名获取当前类的某个field（包括私有字段，不包括父类）
     *
     * @param obj  待处理的对象
     * @param name 字段名
     * @return
     */
    public static Field getDeclaredField(Object obj, String name) throws NoSuchFieldException {
        Field fd = obj.getClass().getDeclaredField(name);
        fd.setAccessible(true);
        return fd;
    }

    /**
     * 获取所有public的field（包括父类）
     *
     * @param obj 待处理的对象
     * @return
     */
    public static Field[] getFields(Object obj) {
        Field[] fds = obj.getClass().getFields();
        for (Field fd : fds) {
            fd.setAccessible(true);
        }
        return fds;
    }

    /**
     * 获取当前类的所有field（包括私有字段，不包括父类）
     *
     * @param obj 待处理的对象
     * @return
     */
    public static Field[] getDeclaredFields(Object obj) {
        Field[] fds = obj.getClass().getDeclaredFields();
        for (Field fd : fds) {
            fd.setAccessible(true);
        }
        return fds;
    }

    /**
     * 获取obj对象当前类的指定字段的值（包括私有字段，不包括父类）。
     *
     * @param obj  待处理的对象
     * @param name 指定字段的名称
     * @return
     */
    public static Object getDeclaredFieldValue(Object obj, String name) throws NoSuchFieldException, IllegalAccessException {
        Field fd = getDeclaredField(obj, name);
        return fd.get(obj);
    }

    /**
     * 获取obj对象当前类的指定字段的值（包括私有字段，不包括父类）。
     *
     * @param obj 待处理的对象
     * @return
     */
    public static Object[] getDeclaredFieldValues(Object obj) throws IllegalAccessException {
        Field[] fds = getDeclaredFields(obj);
        Object[] res = new Object[fds.length];
        for (int i = 0; i < fds.length; i++) {
            res[i] = fds[i].get(obj);
        }
        return res;
    }

    /**
     * 获取obj对象当前类的指定字段的名称数组（包括私有字段，不包括父类）。
     *
     * @param obj 待处理的对象
     * @return
     */
    public static String[] getDeclaredFieldNames(Object obj) throws IllegalAccessException {
        Field[] fds = getDeclaredFields(obj);
        String[] res = new String[fds.length];
        for (int i = 0; i < fds.length; i++) {
            res[i] = fds[i].getName();
        }
        return res;
    }

    /**
     * 获取obj对象当前类的指定字段的名称数组（包括私有字段，不包括父类）。
     *
     * @param clazz 待处理的对象的class
     * @return
     */
    public static <T> String[] getDeclaredFieldNamesWithClass(Class<T> clazz) throws IllegalAccessException {
        Field[] fds = clazz.getDeclaredFields();
        String[] res = new String[fds.length];
        for (int i = 0; i < fds.length; i++) {
            res[i] = fds[i].getName();
        }
        return res;
    }

    /**
     * 获取obj对象当前类的指定字段的值（包括私有字段，不包括父类）。
     *
     * @param obj   待处理的对象
     * @param names 指定字段的名称数组
     * @return
     */
    public static Object[] getDeclaredFieldValues(Object obj, String[] names) throws NoSuchFieldException, IllegalAccessException {
        Object[] res = new Object[names.length];
        for (int i = 0; i < res.length; i++) {
            res[i] = getDeclaredFieldValue(obj, names[i]);
        }
        return res;
    }

    /**
     * 获取obj对象某个public字段的值（包括父类）。
     *
     * @param obj  待处理的对象
     * @param name 指定字段的名称
     * @return
     */
    public static Object getFieldValue(Object obj, String name) throws NoSuchFieldException, IllegalAccessException {
        Field fd = getField(obj, name);
        return fd.get(obj);
    }

    /**
     * 获取obj对象某个public字段的值（包括父类）。
     *
     * @param obj 待处理的对象
     * @return
     */
    public static Object[] getFieldValues(Object obj) throws IllegalAccessException {
        Field[] fds = getFields(obj);
        Object[] res = new Object[fds.length];
        res = new Object[fds.length];
        for (int i = 0; i < res.length; i++) {
            res[i] = fds[i].get(obj);
        }
        return res;
    }

    /**
     * 获取obj对象某个public字段的名称数组（包括父类）。
     *
     * @param obj 待处理的对象
     * @return
     */
    public static String[] getFieldNames(Object obj) throws IllegalAccessException {
        Field[] fds = getFields(obj);
        String[] res = new String[fds.length];
        for (int i = 0; i < res.length; i++) {
            res[i] = fds[i].getName();
        }
        return res;
    }

    /**
     * 获取obj对象某个public字段的名称数组（包括父类）。
     *
     * @param clazz 待处理的对象的class
     * @return
     */
    public static <T> String[] getFieldNamesWithClass(Class<T> clazz) throws IllegalAccessException {
        Field[] fds = clazz.getFields();
        String[] res = new String[fds.length];
        for (int i = 0; i < res.length; i++) {
            res[i] = fds[i].getName();
        }
        return res;
    }

    /**
     * 获取obj对象某个public字段的值（包括父类）。
     *
     * @param obj   待处理的对象
     * @param names 指定字段的名称数组
     * @return
     */
    public static Object[] getFieldValues(Object obj, String[] names) throws NoSuchFieldException, IllegalAccessException {
        Object[] res = new Object[names.length];
        for (int i = 0; i < res.length; i++) {
            res[i] = getFieldValue(obj, names[i]);
        }
        return res;
    }

    /**
     * 设置当前类的指定字段（包括私有字段，不包括父类）的值
     *
     * @param obj   待处理的对象
     * @param name  指定字段的名称
     * @param value 待设置的值
     */
    public static void setDeclaredField(Object obj, String name, Object value) throws NoSuchFieldException, IllegalAccessException {
        Field field = getDeclaredField(obj, name);
        field.set(obj, value);
    }

    /**
     * 设置某个public字段（包括父类）的值
     *
     * @param obj   待处理的对象
     * @param name  指定字段的名称
     * @param value 待设置的值
     */
    public static void setField(Object obj, String name, Object value) throws IllegalAccessException, NoSuchFieldException {
        Field field = getField(obj, name);
        field.set(obj, value);
    }

    /**
     * 获取有参public方法（包括父类），注意invoke时，传入的第一个参数是承载方法的类实例。
     *
     * @param obj            待获取方法所在的类
     * @param name           方法名
     * @param parameterTypes 传入参数的类型
     * @return
     */
    public static Method getMethod(Object obj, String name, Class<?>... parameterTypes) throws NoSuchMethodException {
        return obj.getClass().getMethod(name, parameterTypes);
    }

    /**
     * 获取无参public方法（包括父类），注意invoke时，传入的第一个参数是承载方法的类实例。
     *
     * @param obj  待获取方法所在的类
     * @param name 方法名
     * @return
     */
    public static Method getMethod(Object obj, String name) throws NoSuchMethodException {
        return obj.getClass().getMethod(name);
    }

    /**
     * 获取有参方法（包括私有方法，不包括父类），注意invoke时，传入的第一个参数是承载方法的类实例。
     *
     * @param obj            待获取方法所在的类
     * @param name           方法名
     * @param parameterTypes 传入参数的类型
     * @return
     */
    public static Method getDeclaredMethod(Object obj, String name, Class<?>... parameterTypes) throws NoSuchMethodException {
        Method method = obj.getClass().getDeclaredMethod(name, parameterTypes);
        method.setAccessible(true);
        return method;
    }

    /**
     * 获取无参方法（包括私有方法，不包括父类），注意invoke时，传入的第一个参数是承载方法的类实例。
     *
     * @param obj  待获取方法所在的类
     * @param name 方法名
     * @return
     */
    public static Method getDeclaredMethod(Object obj, String name) throws NoSuchMethodException {
        Method method = obj.getClass().getDeclaredMethod(name);
        method.setAccessible(true);
        return method;
    }

    /**
     * 获取对象的public有参构造函数
     *
     * @param obj            待获取方法所在的类
     * @param parameterTypes 传入参数的类型
     * @return
     */
    public static Object getConstructor(Object obj, Class<?>... parameterTypes) throws NoSuchMethodException {
        return obj.getClass().getConstructor(parameterTypes);
    }

    /**
     * 获取对象的所有public构造函数
     *
     * @param obj 待获取方法所在的类
     * @return
     */
    public static Object[] getConstructors(Object obj) {
        return obj.getClass().getConstructors();
    }

    /**
     * 获取对象的有参构造函数（包括私有构造函数）
     *
     * @param obj            待获取方法所在的类
     * @param parameterTypes 传入参数的类型
     * @return
     */
    public static Object getDeclaredConstructor(Object obj, Class<?>... parameterTypes) throws NoSuchMethodException {
        Constructor<?> constructor = obj.getClass().getDeclaredConstructor(parameterTypes);
        constructor.setAccessible(true);
        return constructor;
    }

    /**
     * 获取对象的所有构造函数（包括私有构造函数）
     *
     * @param obj            待获取方法所在的类
     * @param parameterTypes 传入参数的类型
     * @return
     */
    public static Object[] getDeclaredConstructors(Object obj, Class<?>... parameterTypes) {
        Constructor<?>[] constructors = obj.getClass().getDeclaredConstructors();
        for (Constructor<?> constructor : constructors) {
            constructor.setAccessible(true);
        }
        return constructors;
    }

    /**
     * 获取父类的泛型参数
     *
     * @param obj 父类，如果写在预加载代码块中，则用this。
     */
    public static Type[] getGenericSuperclassParameterizedTypeArgs(Object obj) {
        // 获取父类的泛型
        Type genericSuperclass = obj.getClass().getGenericSuperclass();
        ParameterizedType paramType = (ParameterizedType) genericSuperclass;

        return paramType.getActualTypeArguments(); // 获取父类的泛型参数
    }
}
